PHP tricks
介绍一些PHP基础及CTF中的一些trick
PHP弱类型
1 | '123' == 123 |
AutoConvert
==比较时存在自动类型转换
- 可转化为数字的字符串会转化为数字
- 浮点数表示
- 有包含 ‘.’,’e’ 或 ‘E’ 并且其数字值在整型的范围(PHP_INT_MAX )之内
- 数字开头
- 8进制
- 16进制
- 浮点数表示
- 不可转化为数字的字符串与数字直接返回True
binarysafe and %00 truncation
PHP 中的 string的实现方式是一个由字节组成的数组再加上一个整数指明缓冲区长度
NULL bytes可以处于字符串任何位置
有几个函数会把 NUL 字节之后的数据全都忽略,这些函数是非二进制安全的函数。
- ereg
- strcoll
同时 php 5.3.4- 中,$_GET中的参数获取时会被截断!
常见过滤函数
addslashes()
' " \ NUll
加上’\’处理
htmlspecialchars()
1 | & < > " |
第二个参数 ENT_QUOTES 存在 ,会过滤单引号
- 不过滤
\
反斜杠
mysql_[real_]escape_string
如下字符受影响【\x00】【\n】【\r】【\】【'】【"】【\x1a】
mysql_real_escape_string(string,$con)
mysql_real_escape is much safer than using addslashes
strip_tags(string[,allow])
注释总会被去掉
危险函数
下面的函数都有trick,大部分是出过题目的,例举了几个
部分函数传入数组返回NULL
- substr()
- md5()
strcmp(str1,str2)
str1<str2 返回-1
str1>str2 返回1
str1=str2返回0
比较出错返回NULL,如下传入flag[]=…
1
2
3if (strcmp($_GET['flag'], FLAG) == 0) {
echo "success, flag:" . FLAG;
}
curl()
file://xxx/etc/passwd 不管xxx是啥都是读本地的文件,造成lfi
是弱二进制函数,可以用%00截断
由于还有二次url解码(相当于ssrf),可以用%2500截断
parse_url()
1 | $url=parse_url($_SERVER['REQUEST_URI']); |
preg_match()
preg_match存在贪婪匹配,那么我们可以喂给它一个超长的字符串让它去吃,导致pre_match消耗大量资源从而导致php超时,后面的php语句就不会执行。
1
2max_execution_time = 60 //最大时间设置,0表示无限时间
memory_limit = 128M //最大内存设置- LCTF2017 SignupSystem
若模式中有/e参数则会造成命令执行
在PHP5.4.7以前,preg_replace的第一个参数可以利用\0进行截断,并将正则模式修改为e。
intval()
不能识别除了”e”,数字,小数点,符号以外的字符,遇到则截断
参数过大可造成溢出形成负数,这里涉及到整数溢出
64位上,大于21位的数字
1
<?php echo invatl('4200000000000000000000');?>
in_arrary()
1 | bool in_array(mixed $needle, array $haystack [,bool $strict = FALSE] ) |
在判断时,会自动做类型转换,除非第三个参数为True
1 | if(in_arrary($_GET['typeid'],array(1,2,3,4))) echo "True"; |
如果输入?typeid=1’ union select ….会返回True从而可以注入sql语句
is_numeric()
当遇到hex时直接返回true
存在二次注入及XSS等风险
is_file ()
可以用伪协议绕过php://
switch 语句
auto ascii_to_int
“abcd”–>0
“123Test ”–>123
iconv()
在上传文件的过程中,如果目标使用的字符编码和访客操作系统使用的字符编码不同,可能导致上传后的文件名出现乱码。所以,开发者在获取文件名后,通常调用iconv()对其进行编码转换。 如果转换编码的操作在验证文件名后缀操作之后,那么我们可以利用iconv()特性,截断文件名,进而去除白名单中的后缀,造成文件上传漏洞。
数组永远大于数字
1 | λ php -r "var_dump([]>23333);" |
奇怪的恐龙特性 -安恒5月赛
header()
? PHP的header函数一旦遇到\0、\r、\n这三个字符,就会抛出一个错误
? header之后没有exit的话会继续执行下去
$_REQUEST 覆盖
当 get 和 post 中有一个同名变量 data 时,在 request变量数组 中只会有post 的变量
$_SERVER[‘QUERY_STRING’] bypass
$_SERVER[‘QUERY_STRING’]` 获取的值是未经urldecode的,直接编码一下就饶过了
windows fistword爆破目录
http://www.venenof.com/index.php/archives/523/
webshell构造技巧
死亡exit()绕过
filter流绕过
1 | php://filter/write=string.strip_tags|convert.base64-decode/resource=config.php |
此时,PHP会先用strip_tags去除死亡exit,再将webshell用base64-decode还原,最终写入的文件中不再有死亡exit。
<?php
头部过滤
<script:language=php>
BOM头绕过
BOM(Byte Order Mark)
大部分文本编辑软件都可以显示并编辑UTF-8编码的文件
而windows的记事本,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM).它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码。
在1.php与2.php中输入同样的内容(注释中有中文‘你好’),当然两个文件都可以执行phpinfo()函数
1 | #用记事本保存为utf-8 |
在这些文件开头已经有BOM的文件中,COOKIE无法送出(因为在COOKIE送出前PHP已经送出了文件头),所以登入和登出功能失效.一切依赖COOKIE、SESSION实现的功能全部无效.
检测文件MIME类型的函数
这样文件开头不是<?
,但是mime_content_type
或是fileinfo
函数判断它还是x-php
类型的文件,
mime_content_type(5.3-)
fileinfo(extension=fileinfo)
1
2$fi = new finfo(FILEINFO_MIME_TYPE);
echo $fi->file('1.php');
<?=
作php标签
<?= 的含义为<?php echo
是PHP 5.4.0以后的默认开启(不受short_open_tag选项控制)
注意不用?>结尾
###